#include <fermat/parser/attributes_parser.h>
#include <fermat/parser/attr_token.h>


using fermat::Token;

namespace fermat {
namespace parser {


AttributesParser::AttributesParser(Attributes& attrs, std::istream& istr):
	_attrs(attrs),
	_tokenizer(istr)
{
}


AttributesParser::~AttributesParser()
{
}


void AttributesParser::parse()
{
	const Token* pNext = next();
	if (!isEOF(pNext)) {
		pNext = parseAttributes(pNext);
	}
	if (!isEOF(pNext))
		return ;
}


const Token* AttributesParser::parseAttributes(const Token* pNext)
{
	pNext = parseAttribute(pNext);
	while (isOperator(pNext, OperatorToken::OP_COMMA) || isIdentifier(pNext)) {
		if (!isIdentifier(pNext)) pNext = next();
		pNext = parseAttribute(pNext);
	}
	return pNext;
}


const Token* AttributesParser::parseAttribute(const Token* pNext)
{
	std::string id;
	std::string value;
	pNext = parseIdentifier(pNext, id);
	if (isOperator(pNext, OperatorToken::OP_ASSIGN)) {
		pNext = next();
		if (isOperator(pNext, OperatorToken::OP_OPENBRACE)) {
			pNext = parseComplexAttribute(pNext, id);
		} else if (isIdentifier(pNext) || isLiteral(pNext)) {
			value = pNext->asString();
			pNext = next();
		} else {
			return NULL;
		}
	}
	setAttribute(id, value);
	return pNext;
}


const Token* AttributesParser::parseComplexAttribute(const Token* pNext, const std::string& id)
{
	
	pNext = next();
	std::string oldId(_id);
	if (!_id.empty()) {
		_id.append(".");
		_id.append(id);
	} else {
		_id = id;
	}
	pNext = parseAttributes(pNext);
	_id = oldId;
	if (isOperator(pNext, OperatorToken::OP_CLOSBRACE)) {
		pNext = next();
	} else {
		return NULL;
	}
	
	return pNext;
}


const Token* AttributesParser::parseIdentifier(const Token* pNext, std::string& id)
{
	if (isIdentifier(pNext)) {
		id = pNext->asString();
		pNext = next();
		while (isOperator(pNext, OperatorToken::OP_PERIOD)) {
			id.append(".");
			pNext = next();
			if (isIdentifier(pNext)) {
				id.append(pNext->asString());
				pNext = next();
			} else {
				return NULL;
			}
		}
		return pNext;
	} else {
		return NULL;
	}
}


void AttributesParser::setAttribute(const std::string& name, const std::string& value)
{
	std::string n;
	if (!_id.empty()) {
		n.append(_id);
		n.append(".");
	}
	n.append(name);
	_attrs.set(n, value);
}


} 
}